/**
 *@author   wuwg
 *@createTime   2018/04/07
 *@updateTime   2018/04/11
 *@description  form-item-props public property，form-item的公用属性
 */
import config from '../config/config.js'
import regExps from '../components/form/form-item/reg-exp.js'
import AsyncValidator from 'async-validator'

const formItemPrefixCls = config.prefix + '-form-item'
export default {
  props: {
    /**
     * #property
     *
     * @name    v-model
     * @cn      双向绑定
     * @group   数据
     * @type    text
     * @bind   mustnot
     * @description VUE官方指令，提供数据的双向绑定功能
     */

    // ---------------------------------BEGIN: label-----------------------------------------
    /**
     * #property
     *
     * @name    label
     * @cn      标签
     * @group   标签
     * @type    text
     * @description 标签名称
     */
    label: {
      type: String
    },
    /**
     * #property
     *
     * @name    labelWidth
     * @cn      标签宽度
     * @group   标签
     * @type    numeric
     * @bind    must
     * @description  标签的宽度，单位像素
     */
    labelWidth: {
      type: Number
    },
    /**
     * #property
     *
     * @name    labelPosition
     * @cn      标签位置
     * @group   标签
     * @type    list
     * @options [left,right,top]
     * @description  表单域标签的位置，取值为 [left, right, top]中的其中一个,不选择将从表单控件中继承
     */
    labelPosition: {
      validator (value) {
        return Artery.isOneOf(value, ['left', 'right', 'top'])
      }
    },
    // ---------------------------------END: label-------------------------------------------

    // ---------------------------------BEGIN: validate-------------------------------------------
    /**
     * #property
     *
     * @name    rules
     * @cn      验证规则
     * @group   验证
     * @type    text
     * @bind    must
     * @description 该项数据验证规则，具体配置查看   async-validator:  https://github.com/yiminghe/async-validator
     *  举例：  {required:true,message:'必填项'} || [{required:true,message:'必填项'},{type:‘number’,message:'必须为数值类型'}]
     */
    rules: {
      type: [Object, Array]
    },
    /**
     * #property
     *
     * @name    showMessage
     * @cn      是否显示校验错误信息
     * @group   验证
     * @type    boolean
     * @bind  must
     * @value  true
     * @description 是否显示校验错误信息
     */
    showMessage: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    required
     * @cn      是否必填
     * @group   验证
     * @type    boolean
     * @value   false
     * @description 是否必填，如不设置，则会根据校验规则自动生成
     */
    required: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    doValidate
     * @cn      是否校验
     * @group   验证
     * @type    boolean
     * @value   true
     * @description 是否校验，如不设置，则会根据校验规则进行校验
     */
    doValidate: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    forceValidate
     * @cn      是否强制校验
     * @group   验证
     * @type    boolean
     * @value   true
     * @description 是否强制校验，默认是否
     */
    forceValidate: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    min
     * @cn      最小值
     * @group   验证
     * @type    text
     * @bind    must
     * @description 数据项的数值最小值，或者最小长度
     */
    min: {
      type: Number
    },
    /**
     * #property
     *
     * @name    max
     * @cn      最大值
     * @group   验证
     * @type    text
     * @bind    must
     * @description 数据项的数值最大值，或者最大长度
     */
    max: {
      type: Number
    },
    /**
     * #property
     *
     * @name    validator
     * @cn      函数验证
     * @group   验证
     * @type    text
     * @bind    must
     * @description 数据项的函数验证 validaor:function(rule,value,callback){
     *  //写验证代码。最后执行回调函数，callback 传参说明验证失败，不传参说明验证成功
     *      callback('验证失败！')
     *      }
     */
    validator: {
      type: Function
    },
    /**
     * #property
     *
     * @name      validateOption
     * @cn        常用验证
     * @group     验证
     * @type      list
     * @options    [手机号,邮箱,一代身份证,二代身份证,中文,IP]
     * @description   常用验证，取值为 [手机号,邮箱,一代身份证,二代身份证,中文,IP,邮箱] 中的一个,默认无
     */
    validateOption: {
      validator (value) {
        return Artery.isOneOf(value, ['手机号', '邮箱', '一代身份证', '二代身份证', '中文', 'IP']) || Array.isArray(value)
      }
    }
    // ---------------------------------END: validate-------------------------------------------
  },
  data () {
    return {
      // 验证状态  error, success  validating
      validateState: '',
      // 校验结果信息
      validateMessage: ''
    }
  },
  watch: {
    validateRelated: {
      handler: function () {
        this.validate()
      },
      deep: true,
      immediate: false
    }
  },
  computed: {
    // ---------------------------------BEGIN: form item-----------------------------------------
    /**
     * 获取父级form组件
     */
    form () {
      let parent = this.$parent
      if (parent) {
        while (parent.$options.name !== config.prefix + '-form') {
          parent = parent.$parent
          //  如果不存在父级组件，那么退出循环
          if (!parent) {
            break
          }
        }
      }
      return parent
    },
    formItemClasses () {
      return [
        `${formItemPrefixCls}`,
        {
          [`${formItemPrefixCls}-label-${this.realLabelPosition}`]: this.realLabelPosition,
          [`${formItemPrefixCls}-required`]: this.required,
          [`${formItemPrefixCls}-error`]: this.validateState === 'error'
        }
      ]
    },
    formItemStyles () {
      const style = {}
      if (this.realLabelWidth) {
        style.paddingLeft = `${this.realLabelWidth}px`
      }
      if (this.realLabelPosition == 'top') {
        style.paddingLeft = 'initial'
      }
      return style
    },
    // ---------------------------------END: form item-----------------------------------------

    // ---------------------------------BEGIN: label-----------------------------------------
    labelClasses () {
      return [
        `${formItemPrefixCls}-label`
      ]
    },
    labelStyles () {
      const style = {}
      if (this.realLabelWidth) {
        style.width = `${this.realLabelWidth}px`
      }
      if (this.realLabelPosition == 'top') {
        style.width = 'auto'
      }
      return style
    },
    realLabelWidth () {
      return this.labelWidth || this.labelWidth === 0 ? this.labelWidth : this.form && this.form.labelWidth ? this.form.labelWidth : 0
    },
    realLabelPosition () {
      return this.labelPosition ? this.labelPosition : this.form && this.form.labelPosition ? this.form.labelPosition : ''
    },
    // ---------------------------------END: label-------------------------------------------

    // ---------------------------------BEGIN: validate-----------------------------------------
    errorTipClasses () {
      return [
        `${formItemPrefixCls}-error-tip`
      ]
    },
    errorTipStyles () {
      const style = {}
      if (this.realLabelWidth) {
        style.left = `${this.realLabelWidth}px`
      }
      if (this.realLabelPosition == 'top') {
        style.left = 0
      }
      return style
    },
    isShowMessage () {
      return this.validateState === 'error' && this.showMessage
    },
    validateRelated () {
      const { required, rules, doValidate, forceValidate, min, max, validateOption, validator } = this
      return { required, rules, doValidate, forceValidate, min, max, validateOption, validator }
    }
    // ---------------------------------END: validate-----------------------------------------
  },
  methods: {
    // 获取验证规则
    getRules: function () {
      // 如果存在form组件
      /*
       * let formRules = this.form? this.form.rules:null;
       *formRules = formRules ? formRules[this.prop] : [];
       */
      const selfRules = this.rules
      const inRules = []
      // 如果是必须字段
      if (this.required) {
        inRules.push({
          required: true,
          message: selfRules && selfRules[0].message ? selfRules[0].message : '该项为必填项'
        })
      }

      // 处理最小值和最大值
      const _type = Artery.type(this.value)
      if (Artery.isOneOf(_type, ['string', 'number', 'array']) && (this.min || this.max)) {
        const msgType = `${_type}${this.min || ''}${this.max || ''}`
        const msgCfg = {
          stringMin: `该项长度不能小于${this.min}`,
          stringMax: `该项长度不能大于${this.max}`,
          stringMinMax: `该项长度必须在${this.min}-${this.max}之间`,
          numberMin: `该项值不能小于${this.min}`,
          numberMax: `该项值不能大于${this.max}`,
          numberMinMax: `该项值必须在${this.min}-${this.max}之间`,
          arrayMin: `该项数据长度不能小于${this.min}`,
          arrayMax: `该项数据长度不能大于${this.max}`,
          arrayMinMax: `该项数据长度必须在${this.min}-${this.max}之间`,
        }
        inRules.push({
          type: _type,
          min: this.min || null,
          max: this.max || null,
          message: msgCfg[msgType] || ''
        })
      }

      // 如果是函数
      if (Artery.type(this.validator) === 'function') {
        inRules.push({
          validator: this.validator
        })
      }

      // 如果选了常用验证选项，并且没有自定义掩码
      if (this.validateOption) {
        if (Array.isArray(this.validateOption)) {
          regExps.forEach(item => {
            if (this.validateOption.includes(item.name)) {
              inRules.push({
                pattern: item.reg,
                message: item.msg
              })
            }
          })
        } else {
          const regObj = regExps.filter(item => this.validateOption === item.name)
          if (regObj && regObj.length > 0) {
            inRules.push({
              pattern: regObj[0].reg,
              message: regObj[0].msg
            })
          }
        }
      }

      return [].concat(inRules, selfRules || [])
    },
    // 验证值
    validate (callback) {
      // 处理callback参数
      callback = typeof (callback) === 'function' ? callback : function () {}
      // 获取验证规则
      const rules = this.getRules()
      if (!rules || rules.length === 0 || !this.doValidate || (Artery.isHidden(this.$el) && !this.forceValidate)) {
        callback()
        this.clearValidateInfo() // 修复http://code.thunisoft.com/artery/artery6/issues/113
        return true
      }

      this.validateState = 'validating'
      // 规则描述
      const descriptor = {}
      /*
       *  规则格式 ： descriptor = {
       *                 name: {type: "string", required: true}
       *                 property:rules;
       *          rules:
       *          (一)    type: [string,number,boolean,method,regexp,integer,float,array,object,enum,date,url,hex,email],
       *                            string: Must be of type string. This is the default type.
       *                            number: Must be of type number.
       *                            boolean: Must be of type boolean.
       *                            method: Must be of type function.
       *                            regexp: Must be an instance of RegExp or a string that does not generate an exception when creating a new RegExp.
       *                            integer: Must be of type number and an integer.
       *                            float: Must be of type number and a floating point number.
       *                            array: Must be an array as determined by Array.isArray.
       *                                 //   { required: true, type: 'array', min: 1, message: '至少选择一个爱好' }
       *                            object: Must be of type object and not Array.isArray.
       *                            enum: Value must exist in the enum.
       *                            date: Value must be valid as determined by Date
       *                            url: Must be of type url.
       *                            hex: Must be of type hex.
       *                            email: Must be of type email.
       *           (二)     Required: Boolean,
       *                          The required rule property indicates that the field must exist on the source object being validated.
       *           (三)      Pattern：/^\w+$/;
       *                          The pattern rule property indicates a regular expression that the value must match to pass validation.
       *           (四)      Range:   // type= number
       *                            { type: 'number', min: 1,  max: 100, message: '年龄必须在0-100之间' },
       *                              A range is defined using the min and max properties.
       *                             For string and array types comparison is performed against the length,
       *                             for number types the number must not be less than min nor greater than max.
       *           (五)       Length：20   //  type=字符串和数组类型
       *                           { type: 'string',  len: 5, message: '学校长度为5'},
       *                            To validate an exact length of a field specify the len property.
       *                             For string and array types comparison is performed on the length property,
       *                             for the number type this property indicates an exact match for the number,
       *                             ie, it may only be strictly equal to len.
       *                            If the len property is combined with the min and max range properties, len takes precedence.
       *          (六)        Enumerable： //  type="enum";
       *                              var descriptor = {
       *                                         role: {type: "enum", enum: ['admin', 'user', 'guest']}
       *                                }
       *                              To validate a value from a list of possible values use the enum type with a enum property
       *                               listing the valid values for the field, for example:
       *           (七)       Messages：
       *                             {name:{type: "string", required: true, message: "Name is required"}}
       *                              Depending upon your application requirements,
       *                               you may need i18n support or you may prefer different validation error messages.
       *                             The easiest way to achieve this is to assign a message to a rule:
       *          (八)        validator：
       *                             // you can custom validate function for specified field:
       *                        const fields = {
       *                                asyncField:{
       *                                    validator(rule,value,callback){
       *                                        ajax({
       *                                                url:'xx',
       *                                                value:value
       *                                          }).then(function(data){
       *                                                 callback();
       *                                          },function(error){
       *                                                 callback(new Error(error))
       *                                         });
       *                                        }
       *                                    }
       *                            };
       *               }
       */

      descriptor.data = rules

      const validator = new AsyncValidator(descriptor)

      const model = {}
      // 值
      model.data = this.value
      // validator
      validator.validate(model, { firstFields: true }, (errors, fields, c, d) => {
        this.validateState = !errors ? 'success' : 'error'
        this.validateMessage = errors ? errors[0].message : ''
        // 执行回调函数
        callback(this.validateMessage)
      })
    },
    // 清空校验信息
    clearValidateInfo () {
      this.validateState = ''
      this.validateMessage = ''
    }
  },
  created () {
  }
}
